package ucd.csi.comp30220.fall2011.oteop.flight.impl;

import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;

import ucd.csi.comp30220.fall2011.oteop.OTEOP;
import ucd.csi.comp30220.fall2011.oteop.collision.Collision;
import ucd.csi.comp30220.fall2011.oteop.flight.AlreadyStartedException;
import ucd.csi.comp30220.fall2011.oteop.flight.FailedToStartException;
import ucd.csi.comp30220.fall2011.oteop.flight.Flight;
import ucd.csi.comp30220.fall2011.oteop.flight.FlightException;
import ucd.csi.comp30220.fall2011.oteop.flight.FlightInfo;
import ucd.csi.comp30220.fall2011.oteop.navigation.Position;
import ucd.csi.comp30220.fall2011.oteop.util.EndPoint;
import ucd.csi.comp30220.fall2011.oteop.util.ServiceFinder;

public final class RemoteFlightClient implements Flight {
    
    private Registry registry;
    private RemoteFlight client;
    
    public RemoteFlightClient(final String flightNumber, long timeout) throws Exception {
        EndPoint endPoint = ServiceFinder.findService(
            OTEOP.JMDNS_TYPE_TCP_LOCAL, Flight.JMDNS_SUB_TYPE, flightNumber, timeout);
        
        if (endPoint == null)
            throw new Exception("Failed to get Flight in " +timeout +"ms");
        
        String host = endPoint.getHost();
        int port = endPoint.getPort();
        registry = LocateRegistry.getRegistry(host, port);
        client = (RemoteFlight)(registry.lookup(flightNumber));
    }
    
    public FlightInfo getInfo() throws FlightException {
        try {
            return client.getInfo();
        } catch (RemoteException re) { 
            throw new FlightException("Unable to contact remote Flight", re);
        }
    }
    
    public Position getPosition() throws FlightException {
        try {
            return client.getPosition();
        } catch (RemoteException re) { 
            throw new FlightException("Unable to contact remote Flight", re);
        }
    }

    public double getCourse() throws FlightException {
        try {
            return client.getCourse();
        } catch (RemoteException re) { 
            throw new FlightException("Unable to contact remote Flight", re);
        }
    }

    public int getSpeed() throws FlightException {
        try {
            return client.getSpeed();
        } catch (RemoteException re) { 
            throw new FlightException("Unable to contact remote Flight", re);
        }
    }

    public int getAltitude() throws FlightException {
        try {
            return client.getAltitude();
        } catch (RemoteException re) { 
            throw new FlightException("Unable to contact remote Flight", re);
        }
    }

    public boolean takingOff() throws FlightException {
        try {
            return client.takingOff();
        } catch (RemoteException re) { 
            throw new FlightException("Unable to contact remote Flight", re);
        }
    }

    public boolean inLevelFlight() throws FlightException {
        try {
            return client.inLevelFlight();
        } catch (RemoteException re) { 
            throw new FlightException("Unable to contact remote Flight", re);
        }
    }

    public boolean onFinalApproach() throws FlightException {
        try {
            return client.onFinalApproach();
        } catch (RemoteException re) { 
            throw new FlightException("Unable to contact remote Flight", re);
        }
    }

    public boolean hasLanded() throws FlightException {
        try {
            return client.hasLanded();
        } catch (RemoteException re) { 
            throw new FlightException("Unable to contact remote Flight", re);
        }
    }

    public void start() throws AlreadyStartedException, FailedToStartException {
        try {
            if (client.takingOff() || client.inLevelFlight() || client.onFinalApproach())
                throw new AlreadyStartedException();
            client.start();
        } catch (RemoteException re) { 
            throw new FailedToStartException(re);
        }
    }

    public void setRoute(Position[] waypoints) throws FlightException {
        try {
            client.setRoute(waypoints);
        } catch (RemoteException re) {
            throw new FlightException("Unable to contact remote Flight", re);
        }
    }

    public void setCourse(double course) throws FlightException {
        try {
            client.setCourse(course);
        } catch (RemoteException re) {
            throw new FlightException("Unable to contact remote Flight", re);
        }
    }

    public void setAltitude(int atlitide) throws FlightException {
        try {
            client.setAltitude(atlitide);
        } catch (RemoteException re) {
            throw new FlightException("Unable to contact remote Flight", re);
        }
    }

    public void collisionDetected(Collision collision) throws FlightException {
        try {
            client.collisionDetected(collision);
        } catch (RemoteException re) {
            throw new FlightException("Unable to contact remote Flight", re);
        }
    }
}
